import { useCallback, useEffect, useRef } from 'react';

import * as echarts from 'echarts';
import { debounce } from 'lodash-es';

import type { ECharts, EChartsOption, SetOptionOpts } from 'echarts';

/**
 * ECharts 事件处理函数类型
 */
type EChartsEventHandler = (params: unknown) => void;

/**
 * ECharts 事件映射类型
 */
type EChartsEvents = Record<string, EChartsEventHandler>;

/**
 * ECharts 图片导出类型
 */
type ImageType = 'png' | 'jpeg';

/**
 * ECharts Hook 返回值类型
 */
interface UseEChartsReturn {
  /** DOM 容器引用 */
  domRef: React.RefObject<HTMLDivElement | null>;
  /** 设置图表配置选项 */
  setOptions: (options: EChartsOption, settings?: SetOptionOpts) => void;
  /** 导出图片 */
  exportImage: (type?: ImageType, pixelRatio?: number) => string | undefined;
  /** 导出 CSV 数据 */
  exportCSV: () => void;
}

/**
 * 自定义 React Hook：提供 ECharts 图表功能
 *
 * 功能特性：
 * - 自动初始化和销毁图表实例
 * - 支持容器尺寸变化监听和防抖处理
 * - 支持事件绑定
 * - 支持主题切换
 * - 支持图片导出（PNG/JPEG）
 * - 支持 CSV 数据导出
 *
 * @param events 事件绑定映射（可选）
 * @param theme 图表主题，可以是主题名称字符串或主题对象（可选）
 * @returns 包含 DOM 引用和操作方法的对象
 *
 * @example
 * ```tsx
 * const { domRef, setOptions, exportImage, exportCSV } = useECharts({
 *   click: (params) => console.log('点击事件:', params),
 *   legendSelectChanged: (params) => console.log('图例选择:', params)
 * }, 'dark');
 *
 * // 设置图表配置
 * setOptions({
 *   title: { text: '示例图表' },
 *   series: [{ type: 'line', data: [1, 2, 3, 4, 5] }]
 * });
 *
 * // 导出图片
 * const imageUrl = exportImage('png', 2);
 *
 * // 导出 CSV
 * exportCSV();
 * ```
 */
export function useECharts(events?: EChartsEvents, theme?: string | object): UseEChartsReturn {
  const domRef = useRef<HTMLDivElement | null>(null);
  const chartRef = useRef<ECharts | undefined>(undefined);

  /**
   * 初始化图表实例和事件监听
   *
   * 功能说明：
   * - 创建 ECharts 实例
   * - 绑定用户定义的事件处理器
   * - 监听容器尺寸变化并自动调整图表大小
   * - 在组件卸载时清理资源
   */
  useEffect(() => {
    const container = domRef.current;
    if (!container) {
      console.warn('图表容器不存在，无法初始化图表');
      return;
    }

    // 销毁之前的图表实例（如果存在）
    chartRef.current?.dispose();

    // 创建新的图表实例
    const chart = echarts.init(container, theme);
    chartRef.current = chart;

    // 绑定事件处理器
    if (events) {
      Object.entries(events).forEach(([eventName, handler]) => {
        chart.on(eventName, handler);
      });
    }

    // 创建防抖的 resize 函数，避免频繁调用
    const resizeChart = debounce(() => {
      if (chart && !chart.isDisposed()) {
        chart.resize();
      }
    }, 100);

    // 监听容器尺寸变化
    const observer = new ResizeObserver(() => {
      resizeChart();
    });
    observer.observe(container);

    // 清理函数
    return () => {
      observer.disconnect();
      resizeChart.cancel(); // 取消待执行的防抖函数
      if (chart && !chart.isDisposed()) {
        chart.dispose();
      }
    };
  }, [theme, events]);

  /**
   * 设置图表配置选项
   *
   * @param options ECharts 配置选项对象
   * @param settings 设置选项，如是否合并配置等
   *
   * @example
   * ```tsx
   * setOptions({
   *   title: { text: '销售数据' },
   *   xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },
   *   yAxis: { type: 'value' },
   *   series: [{ type: 'line', data: [120, 200, 150] }]
   * });
   * ```
   */
  const setOptions = useCallback((options: EChartsOption, settings?: SetOptionOpts) => {
    const chart = chartRef.current;
    if (!chart) {
      console.warn('图表实例不存在，无法设置配置选项');
      return;
    }

    if (chart.isDisposed()) {
      console.warn('图表实例已被销毁，无法设置配置选项');
      return;
    }

    chart.setOption(options, settings);
  }, []);

  /**
   * 导出图表为图片
   *
   * @param type 图片格式，支持 'png' 和 'jpeg'
   * @param pixelRatio 像素比例，用于控制图片清晰度
   * @returns 图片的 Data URL，如果导出失败则返回 undefined
   *
   * @example
   * ```tsx
   * // 导出高清 PNG 图片
   * const imageUrl = exportImage('png', 3);
   * if (imageUrl) {
   *   // 可以用于下载或显示
   *   const link = document.createElement('a');
   *   link.href = imageUrl;
   *   link.download = 'chart.png';
   *   link.click();
   * }
   * ```
   */
  const exportImage = useCallback((type: ImageType = 'png', pixelRatio = 2): string | undefined => {
    const chart = chartRef.current;
    if (!chart) {
      console.warn('图表实例不存在，无法导出图片');
      return undefined;
    }

    if (chart.isDisposed()) {
      console.warn('图表实例已被销毁，无法导出图片');
      return undefined;
    }

    try {
      return chart.getDataURL({
        type,
        pixelRatio,
        backgroundColor: '#ffffff',
      });
    } catch (error) {
      console.error('导出图片失败:', error);
      return undefined;
    }
  }, []);

  /**
   * 导出图表数据为 CSV 文件
   *
   * 功能说明：
   * - 提取图表中所有系列的数据
   * - 生成 CSV 格式的数据文件
   * - 自动触发浏览器下载
   */
  const exportCSV = useCallback(() => {
    const chart = chartRef.current;
    if (!chart) {
      console.warn('图表实例不存在，无法导出 CSV');
      return;
    }

    const option = chart.getOption();
    const series = (option.series || []) as Array<{
      name?: string;
      data?: unknown[];
      [key: string]: unknown;
    }>;

    if (!series.length) {
      console.warn('图表中没有数据系列，无法导出 CSV');
      return;
    }

    const rows: string[] = [];
    // CSV 表头
    rows.push(['系列名称', '数据索引', '数据值'].join(','));

    // 遍历所有系列
    series.forEach((seriesItem, seriesIndex) => {
      const seriesName = seriesItem.name || `系列${seriesIndex + 1}`;
      const data = seriesItem.data;

      if (Array.isArray(data)) {
        data.forEach((dataItem: unknown, dataIndex: number) => {
          // 处理不同类型的数据项
          let value: string;
          if (typeof dataItem === 'object' && dataItem !== null) {
            value = JSON.stringify(dataItem);
          } else {
            value = String(dataItem ?? '');
          }

          rows.push(
            [
              `"${seriesName}"`,
              dataIndex.toString(),
              `"${value.replace(/"/g, '""')}"`, // 转义 CSV 中的引号
            ].join(',')
          );
        });
      }
    });

    // 创建并下载文件
    const csvContent = rows.join('\n');
    const blob = new Blob(['\uFEFF' + csvContent], {
      type: 'text/csv;charset=utf-8;',
    }); // 添加 BOM 以支持中文

    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `chart-data-${new Date().getTime()}.csv`;

    // 触发下载
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);

    // 清理资源
    URL.revokeObjectURL(url);
  }, []);

  return { domRef, setOptions, exportImage, exportCSV };
}
